package com.example.test;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.druid.sql.visitor.functions.If;
import com.example.test.bean.BasicArea;
import com.example.test.bean.BasicArea1;
import com.example.test.bean.User;
import com.example.test.config.RabbitMqConst;
import com.example.test.mapper.BasicAreaMapper;
import com.example.test.param.CheckParam;
import com.example.test.param.DataPerm;
import com.example.test.service.AreaService;
import com.example.test.service.LoginService;
import com.example.test.service.build.UserInfo;
import com.example.test.valid.AreaValid;
import com.example.test.实体责任链.AbstractHandel;
import com.example.test.实体责任链.HandelChain;
import com.example.test.布隆过滤基于guava.BloomFilterHelper;
import com.example.test.布隆过滤基于guava.RedisBloomFilter;
import com.example.test.策略模式.HandelContext;
import com.example.test.适配器模式.AdapterComponent;
import com.example.test.适配器模式.SourceBean;
import com.example.test.适配器模式.TargetBean;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.util.concurrent.RateLimiter;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.jasypt.encryption.StringEncryptor;
import org.redisson.api.DefaultNatMapper;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import javax.validation.ValidatorFactory;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

@RestController
@Api(value = "/",description = "默认")
public class Controller implements CheckParam {

    @Autowired
    LoginService loginService;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    BasicAreaMapper basicAreaMapper;

    /**
     * @Description 1 开启redis注解,在启动类上 增加@EnableCaching
     * 2 在查询mysql数据库之前  @Cacheable   cacheNames为缓存在redis中的key , key 为该方法的方法名且当版本冲突时必须加上'' 防止报错
     * @Author FL
     * @Date 11:15 2021/8/26
     * @Param [userId]
     **/

    @ApiOperation(value = "/login",notes = "登录")
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    @Cacheable(cacheNames = "user", key = "'login'")
    public String login(Long userId) {
        String token = UUID.randomUUID().toString();
        UserInfo userInfo = new UserInfo();
        String userJosn = JSONUtil.toJsonStr(userInfo);
        redisTemplate.opsForValue().set("TOKEN:" + token, userJosn, 30 * 60 * 1000, TimeUnit.MILLISECONDS);
        return token;
    }

    @RequestMapping("/getInfoByToken")
    public UserInfo login(String token) {
        Object o = redisTemplate.opsForValue().get("TOKEN:" + token);
        if (o != null) {
            UserInfo userInfo = JSONUtil.toBean(o.toString(), UserInfo.class);
            return userInfo;
        } else {
            return null;
        }
    }

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    HandelContext handelContext;

//    @NoRepeatSubmit
//    @RequestMapping("/getIp")
//    public String getIp(HttpServletRequest request) {
//        String ipAddr = IpUtils.getIpAddr(request);
//        RTopic topic = redissonClient.getTopic("dw", new SerializationCodec());
//        topic.publish("我在学习");
//        // 不释放锁,第一次进入正常访问,再次进入,一直等待,知道删除锁,才可以
////        RLock lock = redissonClient.getLock("123");
////        lock.lock();
//
//        System.out.println(handelContext.dohandel(5));
//        System.out.println(handelContext.dohandel(10));
//        return ipAddr;
//    }

//    @RequestMapping("/shiTu")
//    public Object shiTu() {
//        basicAreaMapper.shitu();
//        List<Map<String, Object>> list = basicAreaMapper.setlectshitu();
//        return list;
//    }

    @Autowired
    AreaService areaService;

//    @RequestMapping("/query/{name}")
//    public Object query(@PathVariable(name = "name") String name) {
//
//        areaService.kajf(name);
//        List<Map<String, Object>> basicArea = basicAreaMapper.query();
//        return basicArea;
//    }

    /**
     * 如果只有一个线程来访问，那么在rLock.tryLock() 这个方法就会阻塞，等锁释放然后再继续下面的操作，
     * 如果是多线程访问，那么在rLock.tryLock() 这个方法会直接返回false不阻塞了,继续往下执行
     *
     * @return
     */
    @GetMapping("/test")
    public Object test() {
        //获取锁实例
        RLock rLock = redissonClient.getLock("lock");

        boolean isLock = false;
        try {
            // 上锁
            isLock = rLock.tryLock();
            System.out.println(Thread.currentThread().getName() + "isLock=" + isLock);
            if (isLock) {
                System.out.println(Thread.currentThread().getName() + "我抢到锁了，开心，先休息10秒先");
                Thread.sleep(10 * 1000);
                // todo service 业务代码

            } else {
                System.out.println(Thread.currentThread().getName() + "被人锁了，郁闷下次再来");
                return "FIELD";
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (isLock) {
                System.out.println(Thread.currentThread().getName() + "不玩了，开锁了！！！");
                // 解锁
                rLock.unlock();
                rLock.forceUnlock();//强制解锁
            }
        }
        return "SUCCESS";
    }


    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    ObjectMapper objectMapper;

    @RequestMapping("/rabbit")
    public Object rabbit() throws JsonProcessingException {
        Message message = MessageBuilder.withBody(objectMapper.writeValueAsBytes("我在学习")).build();
        rabbitTemplate.convertAndSend(RabbitMqConst.DEMO_EXCHANGE, RabbitMqConst.WARN_ROUTING_KEY, message);
        return null;
    }


    @Autowired
    private RedisBloomFilter redisBloomFilter;

    @Autowired
    private BloomFilterHelper bloomFilterHelper;

    @GetMapping("/redis/bloomFilter")
    public Object redisBloomFilter() {
        List<String> allResourceId = Arrays.asList("a", "2", "6", "c", "d", "0");

        for (String id : allResourceId) {
            //将所有的资源id放入到布隆过滤器中
            redisBloomFilter.addByBloomFilter(bloomFilterHelper, "bloom", id);
        }
        return "SUCCESS";
    }


    @GetMapping("/redis/bloomFilter/resourceId")
    public Object redisBloomFilterResourceId(@RequestParam("resourceId") String resourceId) {
        boolean mightContain = redisBloomFilter.includeByBloomFilter(bloomFilterHelper, "bloom", resourceId);
        if (!mightContain) {
            return "RESOURCE_EXSIT";
        }
        return "SUCCESS";
    }

    @Autowired
    private ValidatorFactory validatorFactory;

    @RequestMapping("/validate")
    public Object validate(@RequestBody BasicArea basicArea) {
//    public Object validate(@RequestBody @Validated(AreaValid.update.class)BasicArea basicArea){

        Set<ConstraintViolation<BasicArea>> validate = validatorFactory.getValidator().validate(basicArea, AreaValid.update.class);
        for (ConstraintViolation<BasicArea> basicAreaConstraintViolation : validate) {
            System.out.println(basicAreaConstraintViolation.getPropertyPath() + basicAreaConstraintViolation.getMessage() + basicAreaConstraintViolation.getInvalidValue());
        }
        return "SUCCESS";
    }


    @DataPerm(checkBean = Controller.class, update = true)
    @RequestMapping("/pvalidate")
    public Object pvalidate(@RequestBody BasicArea1 basicArea1) {
//    public Object pvalidate(@RequestBody RequestArea requestArea){

//        boolean flag = this.checkParam(JSONUtil.toJsonStr(basicArea1));

        return "SUCCESS";
    }


    @Override
    public boolean checkParam(String json, boolean update) throws Exception {
        BasicArea1 basicArea1 = JSONUtil.toBean(json, BasicArea1.class);

        if (update) {
            if (StringUtils.isBlank(basicArea1.getId())) {
                throw new Exception("id不能为空");
            }
        }


        return false;
    }


    /**
     * 引入jasypt-spring-boot-starter就会自动注入
     */
    @Resource
    private StringEncryptor stringEncryptor;

    // 加密,可以在此处加密
//    @PostConstruct
    public void StringEncryptor() {
        String encrypt = stringEncryptor.encrypt("Jovision123$");
        System.out.println(encrypt);

        String decrypt = stringEncryptor.decrypt(encrypt);
        System.out.println(decrypt);

        List<Map<String, Object>> query = basicAreaMapper.query();

        System.out.println(query);
    }

    @Autowired
    List<AbstractHandel> abstractHandel;


    //    @PostConstruct
    public void zernliang() {

        HandelChain handelChain = new HandelChain();
        handelChain.addHandel(abstractHandel.get(0));
        handelChain.addHandel(abstractHandel.get(1));
        handelChain.addHandel(abstractHandel.get(2));

        handelChain.doHandel(new User());
    }

    //    @PostConstruct
    public void 简易责任链() {

        for (AbstractHandel handel : abstractHandel) {
            if (!handel.doHandel(null)) {
                break;
            }
        }

    }

    @Autowired
    PlatformTransactionManager platformTransactionManager;

    /**
     * @Description 验证
     * 1 手动开始事务
     * 2 执行
     * 3 提交事务
     * 4 回滚事务
     * @Author FL
     * @Date 15:20 2022/1/7
     * @Param []
     **/
//    @PostConstruct
    public void testshiwu() {
        DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
        TransactionStatus transactionStatus = platformTransactionManager.getTransaction(defaultTransactionDefinition);
        try {
            defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            String id = "1385128181660438529";
            basicAreaMapper.update(id, RandomUtil.randomNumbers(4));
            BasicArea basicArea = basicAreaMapper.selectByPrimaryKey(id);
            System.out.println(JSONUtil.toJsonStr(basicArea));
            if (2 > 1) {
                throw new Exception("sdf");
            }
            platformTransactionManager.commit(transactionStatus);
        } catch (Exception e) {
            platformTransactionManager.rollback(transactionStatus);
        }


    }

//    @Autowired
//    AdapterComponent adapterComponent;
//
//    @PostConstruct
//    public void 适配器转换(){
//
//        SourceBean sourceBean = new SourceBean();
//        sourceBean.setName("我");
//        sourceBean.setTail("不");
//        sourceBean.setHai("认");
//        sourceBean.setLao("狮子");
//        sourceBean.setGui(100);
//        sourceBean.setLai(20);
//
//        adapterComponent.setSourceBean(sourceBean);
//
//        TargetBean targetBean = adapterComponent.getTargetBean();
//
//        System.out.println(JSONUtil.toJsonStr(targetBean));
//
//
//    }


//    @Autowired
//    private RateLimiter orderCreateRateLimiter;

//    public void init(){
//        orderCreateRateLimiter = RateLimiter.create(100);
//    }

//    public void xiadan() throws ExecutionException, InterruptedException {
//        if (!orderCreateRateLimiter.tryAcquire()) {
//
//        }
//
//        String value = redisTemplate.opsForValue().get("key").toString();
//
//        if (StrUtil.isBlank(value)) {
//
//        }
//
//        if (!StrUtil.equals(value,"323")) {
//
//        }
//
//        Future<?> future = Executors.newFixedThreadPool(20).submit(() -> {
//            rabbitTemplate.convertAndSend("1", "2", "订单id去下单");
//        });
//
//        System.out.println(future.get());
//
//    }

}
